﻿namespace Jsl.FxCop
{
    using System;
    using Microsoft.FxCop.Sdk;

    /// <summary>
    /// Finds simple performance issues.
    /// </summary>
    /// <remarks>
    /// Fix 1: Do not call ToString() on a string. This is obviously redundant.
    /// Fix 2: Use EventArgs.Empty instead of new EventArgs().
    /// </remarks>
    public class FixSimplePerformanceChanges : BaseIntrospectionRule
    {
        #region Constructors
        /// <summary>
        /// Initializes a new instance of the <see cref="FixSimplePerformanceChanges"/> class.
        /// </summary>
        public FixSimplePerformanceChanges()
            : base(typeof(FixSimplePerformanceChanges).Name, "Jsl.FxCop.Rules", typeof(FixSimplePerformanceChanges).Assembly)
        {
        }
        #endregion Constructors

        #region Public Methods
        /// <summary>
        /// Checks the specified member.
        /// </summary>
        /// <param name="member">The member.</param>
        /// <returns>The problems found if any.</returns>
        public override ProblemCollection Check(Member member)
        {
            this.Visit(member);

            return this.Problems;
        }

        /// <summary>
        /// Visits the method call.
        /// </summary>
        /// <param name="call">The call being visited.</param>
        public override void VisitMethodCall(MethodCall call)
        {
            if (call == null)
            {
                throw new ArgumentNullException("call");
            }

            if (call.Operands.Count == 0)
            {
                if (call.IsCallTo(WellKnownTypeNames.Object, WellKnownMethodNames.ToString))
                {
                    var memberBinding = call.Callee as MemberBinding;
                    if ((memberBinding != null)
                        && (memberBinding.TargetObject.Type.FullName == WellKnownTypeNames.String))
                    {
                        this.Problems.Add(
                            new Problem(
                                this.GetNamedResolution("String.ToString"),
                                call.SourceContext));
                    }
                }
            }

            base.VisitMethodCall(call);
        }

        public override void VisitConstruct(Construct construct)
        {
            if (construct.Operands.Count == 0)
            {
                (construct.Constructor as MemberBinding)
                    .IfNotNull(memberBinding => memberBinding.BoundMember as InstanceInitializer)
                    .If(initializer => initializer.DeclaringType.FullName == WellKnownTypeNames.EventArgs)
                    .DoIfNotNull(initializer =>
                        this.Problems.Add(
                            new Problem(
                                this.GetNamedResolution("NewEventArgs"),
                                construct.SourceContext)));
            }

            base.VisitConstruct(construct);
        }
        #endregion Public Methods
    }
}